using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Collections.ObjectModel;
using TomShane.Neoforce.Controls;

namespace XGameLibrary
{
    public class InputHandler : Microsoft.Xna.Framework.GameComponent
    {
        #region Mouse Enum Region

        public enum MouseKey
        {
            LeftKey, RightKey
        }

        #endregion

        #region Mouse Field Region

        static MouseState mouseState;
        static MouseState lastMouseState;
        static int scrollWheelValue;
        static int lastScrollWheelValue;

        #endregion

        #region Keyboard Field Region

        static KeyboardState keyboardState;
        static KeyboardState lastKeyboardState;

        #endregion

        #region Game Pad Field Region

        static GamePadState[] gamePadStates;
        static GamePadState[] lastGamePadStates;

        #endregion

        #region Mouse Property Region

        public static MouseState MouseState
        {
            get { return mouseState; }
        }

        public static MouseState LastMouseState
        {
            get { return lastMouseState; }
        }

        public static int ScrollWheelValue
        {
            get { return scrollWheelValue; }
        }

        public static int LastScrollWheelValue
        {
            get { return lastScrollWheelValue; }
        }

        #endregion

        #region Keyboard Property Region

        public static KeyboardState KeyboardState
        {
            get { return keyboardState; }
        }

        public static KeyboardState LastKeyboardState
        {
            get { return lastKeyboardState; }
        }

        #endregion

        #region Game Pad Property Region

        public static GamePadState[] GamePadStates
        {
            get { return gamePadStates; }
        }

        public static GamePadState[] LastGamePadStates
        {
            get { return lastGamePadStates; }
        }

        #endregion

        public static int ScreenWidth;
        public static int ScreenHeight;



        #region Constructor Region

        public InputHandler(Game game, int screenWidth, int screenHeight)
            : base(game)
        {
            ScreenWidth = screenWidth;
            ScreenHeight = screenHeight;
            mouseState = Mouse.GetState();

            keyboardState = Keyboard.GetState();

            gamePadStates = new GamePadState[Enum.GetValues(typeof(PlayerIndex)).Length];

            foreach (PlayerIndex index in Enum.GetValues(typeof(PlayerIndex)))
                gamePadStates[(int)index] = GamePad.GetState(index);
        }

        #endregion

        #region XNA methods

        public override void Initialize()
        {

            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            lastMouseState = mouseState;
            mouseState = Mouse.GetState();

            lastScrollWheelValue = scrollWheelValue;
            scrollWheelValue = Mouse.GetState().ScrollWheelValue;

            lastKeyboardState = keyboardState;
            keyboardState = Keyboard.GetState();

            lastGamePadStates = (GamePadState[])gamePadStates.Clone();
            foreach (PlayerIndex index in Enum.GetValues(typeof(PlayerIndex)))
                gamePadStates[(int)index] = GamePad.GetState(index);

            base.Update(gameTime);
        }

        #endregion

        #region General Method Region

        public static void Flush()
        {
            lastMouseState = mouseState;
            lastKeyboardState = keyboardState;
        }

        #endregion

        #region Mouse Region

        public static Collection<T> HitTest<T>(IEnumerable<TomShane.Neoforce.Controls.Control> controls, int targetX, int targetY) where T : TomShane.Neoforce.Controls.Control
        {
            Collection<T> col = new Collection<T>();
            if (controls == null || controls.Count() == 0)
                return col;
            for (int i = 0; i < controls.Count(); i++)
            {
                TomShane.Neoforce.Controls.Control c = controls.ElementAt(i);
                Collection<T> tmp = HitTest<T>(c.Controls, targetX, targetY);
                if (tmp != null)
                {
                    for (int j = 0; j < tmp.Count; j++)
                        col.Add(tmp.ElementAt(j));
                }
                if (c is T)
                {
                    T t = (T)c;
                    if (t.OriginRect.Contains(targetX, targetY))
                        col.Add(t);
                }
            }
            if (col.Count == 0)
                return null;
            else
                return col;
        }

        private static bool MouseIsValid(Manager manager)
        {
            if (mouseState.X > ScreenWidth ||
                mouseState.X < 0 ||
                mouseState.Y > ScreenHeight ||
                mouseState.Y < 0)
                return false;
            else
                return true;
        }

        public static int GetScrollWheelValueDelta()
        {
            return scrollWheelValue - lastScrollWheelValue;
        }

        public static bool MouseReleased(Manager manager, MouseKey key)
        {
            if (!MouseIsValid(manager)) return false;
            switch (key)
            {
                case MouseKey.LeftKey:
                    return mouseState.LeftButton == ButtonState.Released && lastMouseState.LeftButton == ButtonState.Pressed;
                case MouseKey.RightKey:
                    return mouseState.RightButton == ButtonState.Released && lastMouseState.RightButton == ButtonState.Pressed;
                default:
                    throw new Exception("MouseKey Error!");
            }
        }

        public static bool MousePressed(Manager manager, MouseKey key)
        {
            if (!MouseIsValid(manager)) return false;
            switch (key)
            {
                case MouseKey.LeftKey:
                    return mouseState.LeftButton == ButtonState.Pressed && lastMouseState.LeftButton == ButtonState.Released;
                case MouseKey.RightKey:
                    return mouseState.RightButton == ButtonState.Pressed && lastMouseState.RightButton == ButtonState.Released;
                default:
                    throw new Exception("MouseKey Error!");
            }
        }

        public static bool MouseDown(Manager manager, MouseKey key)
        {
            if (!MouseIsValid(manager)) return false;
            switch (key)
            {
                case MouseKey.LeftKey:
                    return mouseState.LeftButton == ButtonState.Pressed;
                case MouseKey.RightKey:
                    return mouseState.RightButton == ButtonState.Pressed;
                default:
                    throw new Exception("MouseKey Error!");
            }
        }

        #endregion

        #region Keyboard Region

        public static bool KeyReleased(Keys key)
        {
            return keyboardState.IsKeyUp(key) &&
                lastKeyboardState.IsKeyDown(key);
        }

        public static bool KeyPressed(Keys key)
        {
            return keyboardState.IsKeyDown(key) &&
                lastKeyboardState.IsKeyUp(key);
        }

        public static bool KeyDown(Keys key)
        {
            return keyboardState.IsKeyDown(key);
        }

        #endregion

        #region Game Pad Region

        public static bool ButtonReleased(Buttons button, PlayerIndex index)
        {
            return gamePadStates[(int)index].IsButtonUp(button) &&
                lastGamePadStates[(int)index].IsButtonDown(button);
        }

        public static bool ButtonPressed(Buttons button, PlayerIndex index)
        {
            return gamePadStates[(int)index].IsButtonDown(button) &&
                lastGamePadStates[(int)index].IsButtonUp(button);
        }

        public static bool ButtonDown(Buttons button, PlayerIndex index)
        {
            return gamePadStates[(int)index].IsButtonDown(button);
        }

        #endregion
    }
}
